package org.example;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolver;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import org.example.handler.RpcServerHandler;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Hello world!
 */
public class ProducerServer {

    private Map<String, Object> registryMap = new HashMap<>();

    private List<String> classCache = new ArrayList<>();


    public void pulish(String providerPage) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        getProviderClass(providerPage);
        doRegister();


    }

    /**
     * 反射生成本地实例，存储在map中
     *
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public void doRegister() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        if (classCache.size() == 0) return;
        for (String classPath : classCache) {
            Class<?> aClass = Class.forName(classPath);
            String interfaceName = aClass.getInterfaces()[0].getName();
            registryMap.put(interfaceName, aClass.newInstance());
        }
    }

    /**
     * 获取本地class路径
     *
     * @param providerPage
     */
    public void getProviderClass(String providerPage) {
        ClassLoader classLoader = this.getClass().getClassLoader();
        URL resource = classLoader.getResource(providerPage.replaceAll("\\.", "/"));
        File dir = new File(resource.getFile());
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                getProviderClass(providerPage + "." + file.getName());
            } else if (file.getName().endsWith(".class")) {
                String fileName = file.getName().replace(".class", "").trim();
                classCache.add(providerPage + "." + fileName);
            }
        }
    }

    public void startServer() throws Exception {
        NioEventLoopGroup parentGroup = new NioEventLoopGroup();
        NioEventLoopGroup childGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(parentGroup, childGroup)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new ObjectEncoder());
                        pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
                        pipeline.addLast(new RpcServerHandler(registryMap));
                    }
                }).bind(9999).sync().channel().closeFuture().sync();
    }


    public static void main(String[] args) throws Exception {
        ProducerServer producerServer = new ProducerServer();
        producerServer.pulish("org.example.producer");
        producerServer.startServer();
    }
}
